package connect4client.core;

import messages.Message;
import connect4client.commands.Command;
import connect4client.net.ConnectionController;
import connect4client.user.User;

/**
 * Controller.
 * 
 * This singleton represents the kernel of the client. It receives 
 * a message, returns a command and executes it.
 */
public class Controller {
		
		
	/**
	 * Private constructor to provide the semantics needed by the
	 * singleton pattern.
	 */
	public Controller() {
		this.messageConsumer = new MessageConsumer(this);
		this.messageManager = new MessageManager(this);
		this.user = new User();
		this.playerManager = new PlayerManager();
		this.gameManager = new GameManager();
		this.guiMediator = new NullGUIMediator();
	}

	public void forward(Message message){	

		synchronized (messageManager) {
						
			if(messageManager.getLastReceivedId() >= message.getId() && message.getId() >= 0){
				System.err.println("Duplicate Message: " + message);
				return;
			}
			
			synchronized(connectionController) {
				while (connectionController.isReconnecting()) {
					try {
						connectionController.wait();
					} catch (InterruptedException e) {
					}
				}
			}
			
			if (message.getId() >= 0) {
				messageManager.setLastReceived(message.getId());
			}

			if (message.getLastReceivedId() >= 0) {
				messageManager.clearQueueUpTo(message.getLastReceivedId());	
				messageManager.reSendAllAfter(message.getLastReceivedId());
			}
		}
		
		Command command = Command.parse(message, this);		
		command.execute();
	}
	

	public ConnectionController getConnectionController() {
		return this.connectionController;
	}
	
	
	public void setConnectionController(ConnectionController connectionController) {
		this.connectionController = connectionController;
	}
	
	
	public MessageConsumer getMessageConsumer() {
		return messageConsumer;
	}
	
	
	public MessageManager getMessageManager() {
		return messageManager;
	}
	
	
	public User getUser() {
		return user;
	}
	
	
	public GameManager getGameManager() {
		return gameManager;
	}
	

	public PlayerManager getPlayerManager() {
		return playerManager;
	}
	
	public GUIMediator getGUIMediator() {
		return guiMediator;
	}
	
	public void setGUIMediator(GUIMediator guiMediator) {
		this.guiMediator = guiMediator;
	}

	public void shutDown() {
		System.exit(0);
	}

	
	private MessageConsumer messageConsumer;
	private MessageManager messageManager;
	private ConnectionController connectionController;
	private User user;
	private PlayerManager playerManager;
	private GameManager gameManager;
	private GUIMediator guiMediator;
}
